package ph.edu.ics.sp.graphisched.gui;

import java.awt.GridLayout;
import java.awt.Toolkit;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import ph.edu.ics.sp.graphisched.ClassBox;

@SuppressWarnings("serial")
public class CoursesTree extends JPanel {
	protected DefaultMutableTreeNode rootNode;
	protected DefaultTreeModel treeModel;
	protected JTree tree;
	private Toolkit toolkit = Toolkit.getDefaultToolkit();
	public static int LECTURE_MODE = 1;
	public static int LABORATORY_MODE = 2;
	public static int CATEGORY_MODE = 3;
	public static int ROOT_MODE = 0;
	public Icon leafIcon = null, openIcon = null, closedIcon = null;
	
	public CoursesTree() {
		super(new GridLayout(1, 0));

		rootNode = new DefaultMutableTreeNode("Categories");
		treeModel = new DefaultTreeModel(rootNode);
		
		 try {
			leafIcon = new ImageIcon(new File("").getCanonicalPath()+ "\\res\\icons\\leaf.png");
			openIcon = new ImageIcon(new File("").getCanonicalPath()+ "\\res\\icons\\op.png");
			closedIcon = new ImageIcon(new File("").getCanonicalPath()+ "\\res\\icons\\closed.png");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		tree = new JTree(treeModel);

		DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer)tree.getCellRenderer();
		 renderer.setLeafIcon(leafIcon);
		 renderer.setClosedIcon(closedIcon);
		 renderer.setOpenIcon(openIcon);
		 
		 renderer.setLeafIcon(null);
		 renderer.setClosedIcon(null);
		 renderer.setOpenIcon(null);
		 
		 UIManager.put("Tree.leafIcon", leafIcon);
		 UIManager.put("Tree.openIcon", openIcon);
		 UIManager.put("Tree.closedIcon", closedIcon);
		
		 tree = new JTree(treeModel);
		 
		tree.setEditable(false);
		tree.getSelectionModel().setSelectionMode(
				TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
		tree.setShowsRootHandles(true);

		JScrollPane scrollPane = new JScrollPane(tree);
		scrollPane.setColumnHeaderView(new JButton("Courses"));
		add(scrollPane);
	}

	/** Remove all nodes except the root node. */
	public void clear() {
		rootNode.removeAllChildren();
		treeModel.reload();
		tree.setRootVisible(true);
	}

	public void initializeTree() {
		tree.expandPath(tree.getPathForRow(0));
		tree.expandPath(tree.getPathForRow(1));
		tree.setRootVisible(false);
		tree.setSelectionPath(tree.getPathForRow(1));
	}

	/** Remove the currently selected node. */
	public void removeCurrentNode() {
		TreePath currentSelection = tree.getSelectionPath();
		if (currentSelection != null) {
			DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection
					.getLastPathComponent());
			MutableTreeNode parent = (MutableTreeNode) (currentNode.getParent());
			if (parent != null) {
				treeModel.removeNodeFromParent(currentNode);
				return;
			}
		}

		// Either there was no selection, or the root was selected.
		toolkit.beep();
	}

	/** returns the currently selected course. */
	public String getSelectedCourse() {
		String selected = null;

		if (this.selectedMode() == CoursesTree.LECTURE_MODE) {
			selected = tree.getSelectionPath().getLastPathComponent()
					.toString();
		} else if (this.selectedMode() == CoursesTree.LABORATORY_MODE) {
			selected = tree.getSelectionPath().getParentPath()
					.getLastPathComponent().toString();
		}

		return selected;
	}

	public void removeChildren(TreePath currentSelection) {
		DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection
				.getLastPathComponent());
		int childCount = currentNode.getChildCount();
		for (int i = 0; i < childCount; i++) {
			DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) currentNode
					.getChildAt(0);
			treeModel.removeNodeFromParent(childNode);
		}
	}

	public void removeChildren(DefaultMutableTreeNode currentNode) {
		int childCount = currentNode.getChildCount();
		for (int i = 0; i < childCount; i++) {
			DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) currentNode
					.getChildAt(0);
			treeModel.removeNodeFromParent(childNode);
		}
	}

	public void populateLecClasses(ArrayList<ClassBox> lectureClasses,
			DefaultMutableTreeNode parentNode) {
		removeChildren(parentNode);
		int size = lectureClasses.size();
		for (int i = 0; i < size; i++) {
			StringBuffer sb = new StringBuffer();
			sb.append(parentNode.toString());
			sb.append(" - ");
			sb.append(lectureClasses.get(i).getSection());
			if (lectureClasses.get(i).getLaboratories().size() != 0) {
				populateLabClasses(lectureClasses.get(i).getLaboratories(),
						addObject(parentNode, sb.toString(), true));
			} else {
				addObject(parentNode, sb.toString(), true);
			}
		}

	}

	public void populateLecClasses(ArrayList<ClassBox> lectureClasses) {
		TreePath currentPath = tree.getSelectionPath();
		removeChildren(currentPath);
		int size = lectureClasses.size();
		for (int i = 0; i < size; i++) {
			StringBuffer sb = new StringBuffer();
			sb.append(currentPath.getLastPathComponent().toString());
			sb.append(" - ");
			sb.append(lectureClasses.get(i).getSection());
			if (lectureClasses.get(i).getLaboratories().size() != 0) {
				populateLabClasses(lectureClasses.get(i).getLaboratories(),
						addObject(sb.toString()));
			} else {
				addObject(sb.toString());
			}
		}

	}

	public void populateLabClasses(ArrayList<ClassBox> labClasses,
			DefaultMutableTreeNode parentNode) {
		int size = labClasses.size();
		for (int i = 0; i < size; i++) {
			StringBuffer sb = new StringBuffer();
			sb.append(labClasses.get(i).getSubject().getCourseCode());
			sb.append(" - ");
			sb.append(labClasses.get(i).getSection());
			addObject(parentNode, sb.toString(), true);
		}
	}

	public void populateLabClasses(ArrayList<ClassBox> labClasses) {
		TreePath currentPath = tree.getSelectionPath();
		removeChildren(currentPath);
		int size = labClasses.size();
		for (int i = 0; i < size; i++) {
			StringBuffer sb = new StringBuffer();
			sb.append(labClasses.get(i).getSubject().getCourseCode());
			sb.append(" - ");
			sb.append(labClasses.get(i).getSection());
			addObject(sb.toString());
		}
	}

	public void removeClass(ClassBox cb, ArrayList<ClassBox> lecClasses) {
		TreePath path = tree.getPathForRow(0);
		TreePath rootPath = path.getParentPath();
		String category = cb.getSubject().getCategory();
		String courseCode = cb.getSubject().getCourseCode();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) (rootPath
				.getLastPathComponent());
		int rootChildCount = root.getChildCount();
		for (int i = 0; i < rootChildCount; i++) {
			if (root.getChildAt(i).toString().equals(category)) {
				int coursesSize = root.getChildAt(i).getChildCount();
				for (int j = 0; j < coursesSize; j++) {
					if (root.getChildAt(i).getChildAt(j).toString().equals(
							courseCode)) {
						populateLecClasses(lecClasses,
								(DefaultMutableTreeNode) root.getChildAt(i)
										.getChildAt(j));
					}
				}
				break;
			}
		}
	}

	public int getSelectedChildIndex() {
		int index = -1;
		TreePath parentSelection = tree.getSelectionPath().getParentPath();
		DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) (parentSelection
				.getLastPathComponent());
		TreePath currentSelection = tree.getSelectionPath();
		DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection
				.getLastPathComponent());
		index = parentNode.getIndex(currentNode);
		return index;
	}

	/** returns if the current mode is lecture, lab, or category */
	public int selectedMode() {
		int mode = CoursesTree.ROOT_MODE;
		TreePath currPath = tree.getSelectionPath();
		try {
			if (currPath.getLastPathComponent().toString() != null) {
				if (currPath.getPathCount() == 3) {
					return CoursesTree.LECTURE_MODE;
				} else if (currPath.getPathCount() == 4) {
					return CoursesTree.LABORATORY_MODE;
				} else if (currPath.getPathCount() == 2) {
					return CoursesTree.CATEGORY_MODE;
				}
			}
		} catch (NullPointerException e) {
		}
		return mode;
	}

	/** Add child to the currently selected node. */
	public DefaultMutableTreeNode addObject(Object child) {
		DefaultMutableTreeNode parentNode = null;
		TreePath parentPath = tree.getSelectionPath();

		if (parentPath == null) {
			parentNode = rootNode;
		} else {
			parentNode = (DefaultMutableTreeNode) (parentPath
					.getLastPathComponent());
		}

		return addObject(parentNode, child, true);
	}

	public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
			Object child) {
		return addObject(parent, child, false);
	}

	public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
			Object child, boolean shouldBeVisible) {
		DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(child);

		if (parent == null) {
			parent = rootNode;
		}

		// It is key to invoke this on the TreeModel, and NOT
		// DefaultMutableTreeNode
		treeModel.insertNodeInto(childNode, parent, parent.getChildCount());

		// Make sure the user can see the lovely new node.
		if (shouldBeVisible) {
			tree.scrollPathToVisible(new TreePath(childNode.getPath()));
		}
		return childNode;
	}

	class MyTreeModelListener implements TreeModelListener {
		public void treeNodesChanged(TreeModelEvent e) {
			DefaultMutableTreeNode node;
			node = (DefaultMutableTreeNode) (e.getTreePath()
					.getLastPathComponent());

			/*
			 * If the event lists children, then the changed node is the child
			 * of the node we've already gotten. Otherwise, the changed node and
			 * the specified node are the same.
			 */

			int index = e.getChildIndices()[0];
			node = (DefaultMutableTreeNode) (node.getChildAt(index));

			System.out.println("The user has finished editing the node.");
			System.out.println("New value: " + node.getUserObject());
		}

		public void treeNodesInserted(TreeModelEvent e) {
		}

		public void treeNodesRemoved(TreeModelEvent e) {
		}

		public void treeStructureChanged(TreeModelEvent e) {
		}
	}
}
